package cc.plumgo.ss.yo;

import java.util.Vector;

import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.game.LayerManager;

import cc.plumgo.j2me.utils.CustomCanvas;
import cc.plumgo.j2me.utils.CustomScene;
import cc.plumgo.ss.core.Console;
import cc.plumgo.ss.core.Constants;
import cc.plumgo.ss.ui.UIEngine;
import cc.plumgo.ss.yo.entity.Bullet;
import cc.plumgo.ss.yo.entity.Enemy;
import cc.plumgo.ss.yo.entity.EnemyFactory;
import cc.plumgo.ss.yo.entity.Hero;
import cc.plumgo.ss.yo.entity.Item;

public class YoEngine {
	public static final int SCENE_CORRIDOR = 0;
	public static final int SCENE_BASEMENT = 1;
	public static final int SCENE_PLAYGRND = 2;
	public static final int SCENE_NUM = 3;

	private LayerManager layerMana;
	private CustomScene scene;
	private Hero hero;
	private Vector enemies;

	private int sceneIndex = SCENE_CORRIDOR;
	private int enemyIndex;

	private int scrWidth;
	private int scrHeight;

	public YoEngine() {
		scrWidth = CustomCanvas.canvas.getWidth();
		scrHeight = CustomCanvas.canvas.getHeight();
	}

	public void reset(int sIndex) {
		sceneIndex = sIndex;
		layerMana = new LayerManager();
		enemies = new Vector();
		hero = new Hero();
		hero.setLayer(layerMana);
		hero.setPosition(scrWidth / 2 - 100, scrHeight / 2 + 30);
		hero.updateAllPositions();
		scene = new CustomScene(sceneIndex);
		scene.loadScene();
		layerMana.append(scene.tLayer);
		enemyIndex = 0;
		// setViewWindow();
	}

	private void setViewWindow() {
		if (layerMana == null) {
			return;
		}
		int refx = hero.getRefPixelX();
		int refy = hero.getRefPixelY();
		int swidth = scene.tLayer.getWidth();
		int bound = swidth - scrWidth / 3;
		if (refx < 0) {
			hero.setPosition(0, refy);
			return;
		}
		if (refx > bound) {
			hero.setPosition(bound, refy);
			return;
		}

		int x = refx - scrWidth / 6;
		if (x < 0) {
			x = 0;
		} else if (x > swidth - scrWidth) {
			x = swidth - scrWidth;
		}
		layerMana.setViewWindow(x, 0, scrWidth, scrHeight);
		hero.updateAllPositions();
	}

	public void process(Graphics g) {
		// logic
		yoLogic(g);

		// paint
		layerMana.paint(g, 0, 0);
		hero.drawStateBar(g);
	}

	private void yoLogic(Graphics g) {
		setViewWindow();
		hero.logic();
		// produce enemy
		int refx = hero.getRefPixelX();
		if (enemyIndex < Constants.SCENE_ENM_POS[sceneIndex].length) {
			int posx = Constants.SCENE_ENM_POS[sceneIndex][enemyIndex];
			int dis = posx - refx;
			if (dis <= Constants.LOGIC_OUTPUT_DIS) {
				int type = Constants.SCENE_ENM_TYPE[sceneIndex][enemyIndex];
				Enemy enemy = EnemyFactory.createEnemy(type, posx,
						Constants.ENM_INIT_POSY[type]);
				enemy.setLayer(layerMana);
				enemy.createItem(Constants.ENM_ITEMS[sceneIndex][enemyIndex],
						layerMana);
				enemies.addElement(enemy);
				enemyIndex++;
			}
		} else if (enemies.size() == 0) {
			Console.getInstance().getGameListener().recordScreen();
			Console.getInstance().getGameListener().showPage(UIEngine.UI_PASS);
		}

		// enemy logic
		for (int i = 0; i < enemies.size(); i++) {
			Enemy enemy = (Enemy) enemies.elementAt(i);

			if (enemy.isDied()) {
				if (enemy.getItem() == null) {
					enemies.removeElement(enemy);
				} else {
					checkPickup(enemy);
				}
			} else {
				int enmx = enemy.getRefPixelX();
				int dist = enmx - refx;
				int absDist = Math.abs(dist);
				if (absDist > Constants.LOGIC_FINDING_DIS) {
					enemy.setFinding(true);
					enemy.setState(Enemy.ENM_WALK);
				} else if (absDist > Constants.ENM_ATTACK_DIS[enemy.getType()]) {
					enemy.setFinding(false);
					enemy.setManDis(dist);
					enemy.setState(Enemy.ENM_WALK);
				} else if (absDist > Constants.LOGIC_COLLISION_DIS) {
					enemy.setState(Enemy.ENM_ATTACK);
				} else {
					heroJumpAway(enemy, dist);
				}

				enemy.logic();
				checkAttack(enemy);
			}

			if (hero.isDied()) {
				Console.getInstance().getGameListener().showPage(
						UIEngine.UI_OVER);
			}
		}
	}

	private void checkPickup(Enemy enemy) {
		Item item = enemy.getItem();
		if (item.getSprite().collidesWith(hero.getCurrentSprite(), true)) {
			item.setPicked(true);
		}

		if (item.isPicked()) {
			int x = hero.getRefPixelX() + hero.getCurrentSprite().getWidth()
					/ 2 - item.getSprite().getWidth() / 2;
			int y = hero.getRefPixelY()
					- Constants.ITEM_PICK_OFFSET[item.getType()];
			item.setPosition(x, y);
			item.updateAllPositions();
			if (item.getShowDelay() < 0) {
				switch(item.getType()) {
				case Item.ITEM_BASEB : {
					hero.addBullets(5, 0, 0);
					break;
				}
				case Item.ITEM_FOOTB : {
					hero.addBullets(0, 5, 0);
					break;
				}
				case Item.ITEM_BASKETB : {
					hero.addBullets(0, 0, 5);
					break;
				}
				case Item.ITEM_GLASS : {
					hero.addLife();
					break;
				}
				case Item.ITEM_CREAM :
					hero.addBlood();
				}
				item.setVisible(false);
				enemies.removeElement(enemy);
			}
		}
	}

	private void heroJumpAway(Enemy enemy, int dist) {
		if (hero.isJumpFail()) {
			int x = hero.getRefPixelX();
			int y = hero.getRefPixelY();
			hero.setPosition(enemy.getRefPixelX(), enemy.getRefPixelY());
			enemy.setPosition(x, y);
		}
		hero.setAwayDis(dist);
		enemy.stop(Constants.ENM_ATTACKED_DELAY, Enemy.ENM_WALK);
	}

	private void checkAttack(Enemy enemy) {
		Bullet bullet = hero.getBullet();
		if (bullet.getCurrentSprite().collidesWith(enemy.getCurrentSprite(),
				true)) {
			bullet.stop();
			enemy.hurt(Constants.BULLET_HARMS[bullet.getType()]);
		}
		bullet = enemy.getBullet();
		if (bullet.getCurrentSprite().collidesWith(hero.getCurrentSprite(),
				true)) {
			bullet.stop();
			hero.hurt(Constants.ENM_ATTACK_HARM[enemy.getType()]);
		}
	}

	public void input(int key) {
		if (!hero.isStateLock()) {
			hero.input(key);
		}
	}

	public int getSceneIndex() {
		return sceneIndex;
	}
}
